package org.foreningsgatan.genetics.racers.visual;

import static org.foreningsgatan.genetics.racers.Configuration.sHeight;
import static org.foreningsgatan.genetics.racers.Configuration.sWidth;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.geom.Path2D;
import java.awt.geom.Point2D;
import java.util.LinkedList;

import org.foreningsgatan.genetics.SimulationObserver;
import org.foreningsgatan.genetics.racers.Car;
import org.foreningsgatan.genetics.racers.Configuration;
import org.foreningsgatan.genetics.racers.RacingSimulation;
import org.foreningsgatan.genetics.racers.Sources;

public class RacerComponent extends Component implements SimulationObserver {
	private static final long serialVersionUID = -4740944448271723678L;
	
	private RacingSimulation simulation;
	
	private LinkedList<Point2D> trail;
	
	private void zoomIn(Graphics2D g2d, double factor) {
		Car c = simulation.getCar();
		Point2D p = c.getPosition();
		
		double cx = p.getX() + (double) sWidth / 2;
		double cy = p.getY() + (double) sHeight / 2;
		
		g2d.translate((double) sWidth / 2, (double) sHeight / 2);
		g2d.scale(factor, factor);
		g2d.translate(-cx, -cy);
	}
	
	private void drawCar(Graphics2D g2d) {
		Car c = simulation.getCar();
		double x = c.getPosition().getX() + (double) sWidth / 2;
		double y = c.getPosition().getY() + (double) sHeight / 2;
		
		g2d.rotate(c.getSelf().getAngle(), x, y);
		
		g2d.setColor(Color.LIGHT_GRAY);
		g2d.fillRect((int) x - 15, (int) y - 10, 30, 20);
		
		g2d.setColor(Color.BLACK);
		g2d.drawRect((int) x - 15, (int) y - 10, 30, 20);
		
		g2d.setColor(Color.RED);
		
		double a = c.read(Sources.AngleToNextCheckPoint) * Math.PI;
		
		int[] px = new int[20];
		int[] py = new int[20];
		
		for (int i = 0; i < 20; i++) {
			double da = i * a / 20;
			
			px[i] = (int) (x + Math.cos(da) * 20);
			py[i] = (int) (y + Math.sin(da) * 20);
		}
		
		g2d.drawPolyline(px, py, 20);
	}
	
	private void drawCheckpoints(Graphics2D g2d) {
		Polygon poly = new Polygon();
		int carIndex = simulation.getCar().getTargetCheckpointIndex();
		
		int index = 0;
		for (Point2D p: simulation.getCheckpoints().getPoints()) {
			double x = p.getX() + (double) sWidth / 2;
			double y = p.getY() + (double) sHeight / 2;
			
			if (index < carIndex) {
				g2d.setColor(Color.GREEN);
			} else {
				g2d.setColor(Color.BLUE);
			}
			
			g2d.fillOval((int) x - 5, (int) y - 5, 10, 10);
			
			poly.addPoint((int) x, (int) y);
			index++;
		}
		
		g2d.setColor(Color.BLUE);
		g2d.drawPolygon(poly);
	}
	
	private void drawTrail(Graphics2D g2d) {
		if (trail.size() == Configuration.sTrailLength) {
			trail.removeFirst();
		}
		
		trail.add((Point2D) simulation.getCar().getPosition().clone());
		
		Path2D path = new Path2D.Double();
		
		boolean isFirst = true;
		for (Point2D p: trail) {
			if (isFirst) {
				path.moveTo(p.getX() + (double) sWidth / 2, p.getY() + (double) sHeight / 2);
			}
			
			path.lineTo(p.getX() + sWidth / 2, p.getY() + sHeight / 2);
			
			isFirst = false;
		}
		
		g2d.setColor(Color.LIGHT_GRAY);
		g2d.draw(path);
	}
	
	public RacerComponent(RacingSimulation simulation) {
		this.simulation = simulation;
		this.setPreferredSize(new Dimension(sWidth, sHeight));
		this.trail = new LinkedList<Point2D>();
	}
	
	public void paint(Graphics g) {
		Graphics2D g2d = (Graphics2D) g;
		
		g2d.setColor(Color.LIGHT_GRAY);
		g2d.fillRect(0, 0, sWidth, sHeight);
		
		zoomIn(g2d, 1.5);
		
		g2d.setColor(Color.WHITE);
		g2d.fillRect(0, 0, sWidth, sHeight);
		
		drawCheckpoints(g2d);
		drawTrail(g2d);
		drawCar(g2d);
	}

	@Override
	public void update() {
		this.repaint();
	}
}
